package network;
//其他的网络编程的类 都在 net 这个包中

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;

//服务器程序，需要在程序启动的时候，将端口号确定下来
//原因：
//因为客户端是主动的一方，服务器是被动的一方
//所以呢？
//客户端要能知道服务器在哪，才能  “主动的了”
//需要知道哪些东西呢？
// 1、ip地址（服务器所在主机的ip）
// 2、端口号（一个主机上，有多个程序都要进行网络通信，就需要把哪个程序用哪个端口给明确下来）
//而且一个端口不能同时被两个或者多个进程来关联~~（不能重复）
public class UdpEchoServer {
    //对于一个服务器，一上来我们需要做什么工作呢？
    //我们要进行网络通信，呢就需要操纵网卡
    //而操纵网卡就是基于 socket 对象进行展开的
    //接下来实例化一个类作为 UdpEchoServer 这个服务器的成员变量
    private DatagramSocket socket = null;


    //SocketException异常继承于IOException
    //说明网络编程也属于 io 操作
    //io 是一个很广泛的概念
    public UdpEchoServer(int port) throws SocketException {
        //在构造方法里面进行实例化
        //一方面可以处理异常，另一方面还需要传入一个参数  （端口号）
        this.socket = new DatagramSocket(port);

    }
    //服务器还需要不停的去处理请求，不停的返回响应  期限（7 * 24）

    public void start() throws IOException {
        System.out.println("服务器启动！！！");
        while (true) {
            //1）读取请求并解析
            byte[] bytes = new byte[4096];//“空盘子”
            //接受的数据保存在 数组里面
            //requestPacket 这个对象是一个UDP数据报
            //里面就包含两个部分：
            //1)报头（通过类的属性来表示）
            //2）载荷（通过构造方法传递的字符数组，作为持有载荷的空间）
            DatagramPacket requestPacket = new DatagramPacket(bytes, 4096);
            /*
            括号里面需要填写输出型参数
            从此套接字接收数据报（如果没有接收到数据报 ，该⽅法会阻塞等待）
             */
            socket.receive(requestPacket);

            //此时requestPacket里面存储的是二进制数据，为了方便Java代码中处理，可以把上述数据报中的二进制数据，拿出来，构造为String
            String requst = new String(requestPacket.getData(), 0, requestPacket.getLength());

            //2）根据请求计算响应
            //可以写成一个单独的方法
            String response = process(requst);

            //3）把响应写会到客户端
            //要想发送，也需要实例化一个 DatagramPacket 对象
            //括号里面需要放一个有数据的字节数组
            DatagramPacket responsePacket = new DatagramPacket(
                    response.getBytes(),
                    0,
                    response.getBytes().length,
                    requestPacket.getSocketAddress());
            /*
            requestPacket.getSocketAddress()
            这个方法返回的对象里面就包含了 IP 和 端口号
             */
            socket.send(responsePacket);

            //打印个日志
            //IP地址、端口号、请求、响应
            System.out.printf("[%s:%d] req = %s,resp = %s\n",
                    requestPacket.getAddress(),
                    requestPacket.getPort(),
                    requst,
                    response);
        }

    }

    //由于当前写的是“回显服务器”
    //请求和响应是一样的
    //所以 请求是什么，响应就返回什么
    public String process(String requst) {
        return requst;
    }


    public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(9090);
        server.start();
    }
}


